package org.haifi.game.compiler;

import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.haifi.game.channel.GameCmdInvoker;
import org.haifi.game.reflection.GameReflect;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.google.common.collect.Maps;

/**
 * 动态生成cmd调用实现类
 * 
 * @author joycube2
 * 
 */
@Component
@Lazy(false)
@DependsOn("gameReflect")
public class GameCmdInvokerFactory {

	public GameCmdInvokerFactory() {
		log.info("GameCmdInvokerFactory init");
	}

	@SuppressWarnings("unchecked")
	@PostConstruct
	public Map<Short, GameCmdInvoker> generateGameCmdInvoker() {
		if (cache != null) {
			log.info("use generated object instance");
			return cache;
		}
		log.info("genrating GameCmdInvoker.");
		cache = Maps.newConcurrentMap();
		for (Short cmdId : GameReflect.getAllCmdIds()) {

			String className = "GameCmdInovker" + cmdId;
			String actionName = GameReflect.getGameBaseAction(cmdId).getClass()
					.getSimpleName();
			String methodName = GameReflect.getMethod(cmdId).getName();
			String paramName = GameReflect.getParamCmdIds().get(cmdId)
					.getSimpleName();

			StringBuilder sb = new StringBuilder();
			sb.append("package org.haifi.game.channel;");

			sb.append("import org.haifi.game.action.GameBaseAction;");
			sb.append("import org.haifi.game.action." + actionName + ";");
			sb.append("import org.haifi.game.pb." + actionName + "."
					+ paramName + ";");

			sb.append("import com.google.protobuf.MessageLite;");
			sb.append("import com.google.protobuf.MessageLite.Builder;");

			sb.append("public class " + className
					+ " implements GameCmdInvoker {");
			sb.append("	private " + actionName + " gameAction;");

			sb.append("	public void setGameAction(GameBaseAction action) {");
			sb.append("		this.gameAction = (" + actionName + ") action;");
			sb.append("	}");

			sb.append("	public Builder invokeAction(MessageLite param) {");

			if (GameReflect.getReturnCmdIds().containsValue(cmdId)) {
				// 返回值不为void
				sb.append("		return gameAction." + methodName + "(("
						+ paramName + ") param);");
			} else {
				// 返回值为void
				sb.append("		  gameAction." + methodName + "((" + paramName
						+ ") param);");
				sb.append("return null;");
			}

			sb.append("	}");

			sb.append("}");

			String code = sb.toString();
			log.info(code);
			String name = "org.haifi.game.channel." + className;

			GameCmdInvoker gameCmdInvoker = (GameCmdInvoker) JavaCompilerUtil
					.compiler(name, code);
			gameCmdInvoker.setGameAction(GameReflect.getGameBaseAction(cmdId));

			cache.put(cmdId, gameCmdInvoker);
		}
		return cache;
	}

	private Map<Short, GameCmdInvoker> cache = null;

	private static final Log log = LogFactory
			.getLog(GameCmdInvokerFactory.class);
}
